/*file chiron src/flash.js */
/*preamble

    Copyright (c) 2002-2008 Kris Kowal <http://cixar.com/~kris.kowal>
    MIT License
    
    The license terms are stated in full in <license.rst> and at the end
    of all source files.

*/

include('base');
include('event');
include('environment');
include('http');
include('browser');
var urls = require('urls');

/*** bridge
    hides and loads a given Flash movie by URL and calls
    a given callback after the movie has sent its ready
    signal.  The callback's arguments are a sender
    and receiver object.  Augmenting the receiver with
    handler functions will permit the movie to send signals
    to javascript using your functions.  The sender
    is a similar object provided by the Flash movie that
    contains handler functions that you can call to send
    signals to ActionScript in the Flash movie.
*/
exports.bridge = function (url, observer) {
    queue.push([url, observer]);
    timeoutHandle = setTimeout(function () {
        apply(loading, function (url, observer) {
            environment.print(
                "flash.js: failed to load " + repr(url) +
                " in the given " + timeout + " miliseconds.",
                'error'
            );
            loading = undefined;
            loadNext();
        });
    }, timeout);
    loadNext();
};

if (urls.parse(url).protocol == 'file') {
    warn("flash.js: movies tend not to load from local file:/// URL's");
}

/* since all flash movies will use the same API to register their
 * readieness and connect their senders and receivers, we linearize
 * movie loading.  This involves having a queue of movies that
 * are waiting for one another to finish loading. */

/* undefined or [url, observer] for the currently loading movie */
var loading;

/* a queue of [url, observer] tuples for movies that are waiting to load */
var queue = [];

var timeout = 2000;
var timeoutHandle;

/* a function that queues up the next movie to load, as long as another movie
 * isn't in the process of loading. */
var loadNext = function () {
    if (!loading && queue.length) {
        loading = queue.shift();
        apply(loading, function (url, observer) {
            createMovie(url);
        });
    }
};

/* a mapping of ids (as created by connect) to corresponding receiver objects 
 * so that the movie can send messages to it */
var receivers = dict();

/* set up a flash object in the global object tree to receive
 * messages from Flash */
window.__flash__bridge = {};

/* a handler for receiving messages from Flash for particular 
 * movies */
window.__flash__bridge.receive = function (id, method, args) {
    try {
        var context = receivers.get(id);
        context[method].apply(context, args);
    } catch (exception) {
        setTimeout(function () {
            throw exception;
        }, 10);
    }
};

/* a signal that a Flash movie sends when it's finished loading and
 * exposing its API */
window.__flash__bridge.ready = function () {
    clearTimeout(timeoutHandle);
    try {
        apply(loading, function (url, observer) {
            var receiver = {};
            receivers.set(url, receiver);
            var sender = getMovie(url);
            observer(sender, receiver);
            /* notify the movie that a receiver has been created */
            sender.register(url);
        });
        loading = undefined;
        loadNext();
    } catch (exception) {
        /* since we're in Flash's execution stack, our exception
         * won't make it back to Javascript.  throw it later. */
        setTimeout(function () {
            throw exception;
        }, 10);
    }
};

var getMovie = function (id) {
    if (isIE) {
        return window[id];
    } else if (isSafari) {
        return document[id + '-embed']
    } else {
        return document.getElementById(id + '-embed')
    }
};

var createMovie = function (url) {
    var id = url;
    var target = (document.body ? document.body : document.getElementsByTagName('div')[0]);
    if (!target) throw new Error("No target for Sound Manager movie in DOM");

    var element = document.createElement('div');
    element.className = 'movieContainer';

    /* "hide" flash movie */
    element.style.position = 'absolute';
    element.style.left = '0px';
    element.style.top = '0px';
    element.style.width = '0px';
    element.style.height = '0px';
    element.style.visibility = 'hidden';

    var objectHtml = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8, 0, 0, 0" width="16" height="16" id=' + enquote(id) + '><param name="movie" value=' + enquote(url) + '><param name="quality" value="high"><param name="allowScriptAccess" value="always" /></object>';
    var embedHtml = '<embed name=' + enquote(id + '-embed') + ' id=' + enquote(id + '-embed') + ' src=' + enquote(url) + ' width="1" height="1" quality="high" allowScriptAccess="always" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash"></embed>';

    try {
        target.appendChild(element);
        element.innerHTML = isIE ? objectHtml : embedHtml;
    } catch (exception) {
        /* may fail under app/xhtml+xml - has yet to be tested */
        throw new Error(
            'createMovie: appendChild/innerHTML set failed. ' +
            'Serving application/xhtml+xml MIME type? Browser ' + 
            'may be enforcing strict rules, not allowing write ' +
            'to innerHTML. (PS: If so, this means your commitment ' + 
            'to XML validation is going to break stuff now, because ' +
            'this part isn\'t finished yet.'
        );
    }
};

/**
    References
    ----------

    http://www.schillmania.com/projects/soundmanager2/
    Scott Shiller's Sound Manager 2.  This is the origin of this
    module, although very little of the original code remains.

*/


/*license

    Legal
    =======
    
    Chiron is a component of the Tale web-game project.
    
    See <credit.txt> for a complete list of
    contributions and their licenses.  All contributions are provided
    under permissive, non-viral licenses including MIT, BSD, Creative Commons
    Attribution 2.5, Public Domain, or Unrestricted.
    
    
    License
    =======
    
    Copyright (c) 2002-2008 Kris Kowal <http://cixar.com/~kris.kowal>
    MIT License
    
    
    MIT License
    -----------
    
    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:
    
    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

